<template>
  <div class="process-detail-form" id="process-detail-form">
    <a-row class="process-detail-form-row">
      <a-col :span="20" class="process-detail-form-col">
        <div class="process-detail-form-header">
          <div class="back-area">
            <a-button type="link" class="back-btn" @click="handleBack">《 {{ t('back') }}</a-button>
          </div>
          <div v-if="title.firstName" class="process-detail-form-header-title">
            <span>{{ title.firstName }}</span>
            <span>{{ title.secondName }}</span>
          </div>
        </div>
        <div class="process-detail-form-content">
          <!-- 审批内容区 -->
          <component
              class="main-root"
              ref="formRef"
              :is="`${state.type}${state.pageId}`"
              :id="state.formData.id"
              :processInstanceId="processInstanceId"
              editType="edit"
              :formData="state.formData"
              :isProcess="true"
          />
          <FormModalAction
              class="process-detail-form-content-operate"
              :processStatus="processIdInfo.processStatus"
              :isInitiatorUser="isInitiatorUser"
              :isShowUrge="isShowUrge"
              :isMinePage="isMinePage"
              :isCurrentOperatorUser="isCurrentOperatorUser"
              :isStartNode="isStartNode"
              :basePermission="processDetail?.currentNode?.basePermission"
              :approve-button-config="state.approveButtonConfig"
              @approve="handleApproveButtonClick"
          />
        </div>
      </a-col>
      <a-col :span="4" class="process-detail-form-col approval-history-wrapper">
        <approval-history
            v-if="!isNullOrEmpty(processDetail)"
            :approve-task-list="processDetail.processTaskList"
        />
      </a-col>
    </a-row>
    <a-modal
        :visible="state.approvalCommentsModalVisible"
        :width="432"
        :centered="true"
        :mask-closable="true"
        :title="t('workflow.leavingMessage')"
        wrap-class-name="approval-comments-modal"
        @cancel="handleCancelApprove"
        :get-container="getContainer"
    >
      <template #footer>
        <a-button class="default-btn" @click="handleCancelApprove">
          {{ t('cancel') }}
        </a-button>
        <a-button
            type="primary"
            :danger="currentApproveAction.isDanger || false"
            :class="[state.approvalActionType === 'APPROVE' ? 'agree-btn' : 'danger-btn']"
            :loading="state.confirmApprovalLoading"
            @click="currentApproveAction.action"
        >
          <template #icon>
            <component :is="currentApproveAction.icon" />
          </template>
          {{ currentApproveAction.title }}
        </a-button>
      </template>
      <div class="process-info-warp">
        <div class="process-form-item">
          <span class="approval-comments">{{ t('workflow.approveRemark') }}</span>
          <a-textarea
              v-model:value="state.approveRemark"
              :placeholder="t('placeholderInput')"
              :auto-size="{ minRows: 7, maxRows: 7 }"
          />
          <div v-if="state.approvalActionType === 'ROLLBACK' && !state.isPreNode" class="option">
            <span class="title"> {{ t('workflow.backNode') }}</span>
            <div class="form-item">
              <a-select
                  style="width: 50%"
                  :options="state.approveBackNodeList"
                  @change="handleBackNodeChange"
              />
            </div>
          </div>
        </div>
      </div>
    </a-modal>
  </div>
</template>

<script lang="ts">
import { defineComponent, ref, reactive, computed, onMounted, Ref, UnwrapNestedRefs, nextTick } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { useI18n } from 'vue-i18n'
import { isNullOrEmpty } from '@/utils/is'
import FormModalAction from './FormModalAction'
import ApprovalHistory from './ApprovalHistory.vue'
import { message } from 'ant-design-vue'
import {
  fetchProcessDetail,
  processCancel,
  processInstanceRollback,
  setProcessApproval,
  setProcessUrge,
  fetchProcessFormState,
  changeProcessFormState
} from '@/apis/sys/process'
import { useUserStore } from '@/store/modules/user'
import { findIndex } from 'lodash-es'
import { ApproveTabTypeEnum } from '@/enums/process'
import { getAppBaseUrl } from '@/utils/index';

// 批量注册表单组件
const files = import.meta.globEager('../../../page/*.vue')
const formFiles = import.meta.globEager('../../../form/*.vue')
// 当前应用下全部表单组件
const fromComponents: Record<string, any> = {}
// 遍历生成对象集合
for (const key in files) {
  const component = files[key].default
  let name = key.substring(key.lastIndexOf('/') + 1, key.lastIndexOf('.vue'))
  component.name = name
  fromComponents[name] = component
}
// 遍历表单
  for (const key in formFiles) {
    const component = formFiles[key].default
    let name = key.substring(key.lastIndexOf('/') + 1, key.lastIndexOf('.vue'))
    component.name = name
    fromComponents[name] = component
  }

// 表单提交数据对象
interface ParamsData {
  pageId: string
  applicationId: number
  processInstanceName: string
  bodyConfig: Array<{ key: string; value: any }>
  // 处理子表单
  childrenList: Array<{ key: string; value: any }>
}
interface ApprovalStrategy {
  title: string
  icon: string
  isDanger?: boolean
  // 点击确认审批意见弹窗所执行的动作
  action: () => void
  // 处理不同类型审批动作的逻辑（部分不需要打开审批意见弹窗）
  handleApprove: () => void
}
interface ProcessDetailState {
  pageId: number // 需要渲染的页面ID
  type: 'Page' | 'Form' // 页面类型
  id?: number // 编辑时的id
  formData: Record<string, any> // 流程中的数据 （暂无）
  approveRemark: string // 审批意见
  backTargetNode: string // 回退节点信息
  confirmApprovalLoading: boolean // 确认弹窗loading
  approvalCommentsModalVisible: boolean // 审批意见弹窗显隐
  approveBackNodeList: any[] // 回退节点列表
  isPreNode: boolean // 是否退回上一节点
  approvalActionType: ApprovalActionType // 审批动作类型
  approveButtonConfig: ButtonSetting[] // 审批按钮配置
}
export default defineComponent({
  name: 'ProcessDetail',
  components: {
    FormModalAction,
    ...fromComponents,
    ApprovalHistory
  },
  setup() {
    const route = useRoute()
    const router = useRouter()
    const { t } = useI18n()
    // 从路由中获取信息
    const { processInstanceId, taskId, processStatus } = route.params
    const processIdInfo = { processInstanceId, taskId, processStatus }

    const userStore = useUserStore()
    const formRef = ref<{
      formRef: Ref
      formState: UnwrapNestedRefs<any>
      subFormMap: Record<string, string | number>
      getParams: (formState: object) => ParamsData
      handleSubmit: (exc: (data: ParamsData) => void) => void
      onSubmit: () => void
      resetForm: () => void
      clearCache: () => void
      controlFormItemVisible: (key: string, visible: boolean) => void
      controlFormItemDisabled: (key: string, disabled: boolean) => void
    } | null>(null)
    const processDetail = ref({})

    const state = reactive<ProcessDetailState>({
      pageId: 0,
      id: 0,
      type: 'Page',
      formData: {},
      confirmApprovalLoading: false,
      approvalCommentsModalVisible: false,
      approvalActionType: 'APPROVE',
      approveRemark: '',
      backTargetNode: '',
      isPreNode: true,
      approveBackNodeList: [],
      approveButtonConfig: []
    })
    const title = computed<{ firstName: string; secondName: string }>(() => {
      if (isNullOrEmpty(processDetail.value)) {
        return { firstName: '', secondName: '' }
      }

      return {
        firstName: processDetail.value?.processName ? `${processDetail.value?.processName} / ` : '',
        secondName: processDetail.value?.currentNode?.processNodeName
      }
    })

    const currentTaskNode = computed(() => {
      if (!processDetail?.value?.processTaskList || !taskId) {
        return {}
      }

      return (
          processDetail.value.processTaskList.filter(item => {
            return item.taskId === taskId
          }) || []
      )
    })

    // 是不是组织机构 表单
    const isOrganization = computed(() => {
      return processDetail.value && processDetail.value.pageType === 'ORGANIZATION'
    })

    // 是否是当前流程的发起人
    const isInitiatorUser = computed(() => {
      const userInfo = userStore.getUserInfo
      return findIndex(currentTaskNode.value, { assignUserId: userInfo?.id }) !== -1
    })
    // 是否显示催办 撤回按钮
    const isMinePage = computed(() => {
      // 当前没有
      return processIdInfo.processStatus === ApproveTabTypeEnum.MyInitiated && processDetail.value?.processStatus === 'IN_PROCESS'
    })
    const isShowUrge = computed(() => {
      // 当前没有
      return processIdInfo.processStatus === ApproveTabTypeEnum.MyInitiated && !processDetail.value.urge
    })
    // 获取当前登录用户是否是当前审批节点用户
    const isCurrentOperatorUser = computed(() => {
      const userInfo = userStore.getUserInfo
      return findIndex(currentTaskNode.value, { assignUserId: userInfo?.id }) !== -1
    })
    // 是否显示流程提交按钮
    const isStartNode = computed(() => {
      return false
    })
    // 获取流程信息
    const getProcessDetail = (processInfo: {
      processInstanceId: string
      taskId: string
      processStatus: string
    }) => {
      const { processInstanceId, taskId } = processInfo
      fetchProcessDetail({ processInstanceId, taskId }).then((response: ProcessDetail) => {
        if (isNullOrEmpty(response) || isNullOrEmpty(response.data)) {
          // 处理无数据错误
          message.error(t('noProcessError'))
          return
        }
        const processInfo = response.data.currentNode || {}
        const { pageConfig } = processInfo
        processDetail.value = response.data
        let url = processIdInfo.processStatus === ApproveTabTypeEnum.MyInitiated ? pageConfig.urlPcDetail : pageConfig.urlPc
        state.pageId = Number(url.split('/').pop().replace(/[^\d]/g, ' '))
        const type = url.split('/')[1]
        state.type = type ? type.charAt(0).toUpperCase() + type.slice(1) : 'Page'
        state.approveButtonConfig = processInfo.approveButtonConfig.buttonSetting

        if (state.type === 'Form') {
            fetchProcessFormState(processInstanceId).then(res => {
              if (isNullOrEmpty(res) || isNullOrEmpty(res.data)) {
                  // 处理无数据错误
                  message.error(t('noProcessDataError'))
                  return
                }
                const result = {}
                res.data.bodyConfig.forEach(item => {
                  result[item.key] = item.value
                })
                // 处理子表单数据
              if (formRef?.value?.subFormMap && res.data.childrenList) {
                const pageIdKeyMap = {}
                Object.keys(formRef?.value?.subFormMap).forEach(key => {
                  pageIdKeyMap[formRef?.value?.subFormMap[key]] = key
                })
                res.data.childrenList.forEach(item => {
                  const fieldKey = pageIdKeyMap[item.pageId]
                  if (!fieldKey) {
                    return
                  }
                  if (!result[fieldKey]) {
                    result[fieldKey] = []
                  }
                  const subformItem = {}
                  item.bodyConfig.forEach(subItem => {
                    subformItem[subItem.key] = subItem.value
                  })
                  result[fieldKey].push(subformItem)
                })
              }
                state.id = res.data.id
                state.formData = result
            })
          }

        // 是否退回上一节点
        state.isPreNode = processInfo?.basePermission?.rollbackNodeRange === 'ONE_BEFORE_NODE'

        const approveBackNodeList = []
        processDetail?.value?.processTaskList &&
        processDetail.value.processTaskList.forEach(item => {
          // 排除当前节点及重复节点
          if (
              item.assignStatus !== 'WAIT_HANDLE' &&
              findIndex(approveBackNodeList, { value: item.processNodeId }) === -1
          ) {
            approveBackNodeList.push({
              value: item.processNodeId,
              label: item.taskName
            })
          }
        })
        state.approveBackNodeList = approveBackNodeList
        nextTick(() => {
            if (state.type === 'Form') {
              // 处理字段隐藏及禁用
              const { pageFieldIdList } = processInfo
              pageFieldIdList &&
                pageFieldIdList.forEach(fieldState => {
                  if (formRef.value && formRef?.value) {
                    formRef?.value?.controlFormItemVisible(fieldState.filedId, fieldState.visibilityFlag)
                    formRef?.value?.controlFormItemDisabled(fieldState.filedId, !fieldState.editableFlag)
                  }
                })
            }
          })
      })
    }

    onMounted(() => {
      getProcessDetail({ ...processIdInfo })
    })

    // 保存数据
      const handleSaveProcessFormData = () => {
        return new Promise(resolve => {
          // 只处理表单的同意跟提交两个动作
          if (state.type === 'Form' && ['APPROVE', 'SUBMIT'].includes(state.approvalActionType)) {
            const params = formRef.value.getParams()
            state.id && (params.id = state.id)
            params.triggerAction = 'EDIT'
            params.pageDataIdList = [state.pageId]
            changeProcessFormState({
              processInstanceId: processIdInfo.processInstanceId,
              formData: params
            }).then(res => {
              resolve(res.data)
            })
          } else {
            resolve(true)
          }
        })
      }

    // 流程表单 审批处理 同意、拒绝、撤销、回退
    const handleApproveRejectRevokeConfirm = async () => {
      // 判断是否有审批意见
      if (!state.approveRemark) {
        message.error(t('workflow.approveRemarkEmpty'))
        return
      }
      // 报错流程过程中的修改数据，仅在同意时保存
      await handleSaveProcessFormData()
      const data: {
        processInstanceId: string
        taskId: string
        approveAction: string
        approveRemark: string
        rollbackTaskKey?: string
      } = {
        approveAction: state.approvalActionType,
        approveRemark: state.approveRemark,
        processInstanceId: processIdInfo.processInstanceId as string,
        taskId: processIdInfo.taskId as string
      }
      state.confirmApprovalLoading = true

      // 如果是回退
      if (state.approvalActionType === 'ROLLBACK') {
        // 判断退回时是否有审批意见
        if (!state.approveRemark) {
          message.error(t('workflow.approveRemarkEmpty'))
          state.confirmApprovalLoading = false
          return
        }

        // isPreNode
        if (!state.isPreNode && !state.backTargetNode) {
          message.error(t('workflow.checkError.noSelectBackNode'))
          state.confirmApprovalLoading = false
          return
        } else {
          data.rollbackTaskKey = state.backTargetNode
        }
      }

      const usedAPi =
          state.approvalActionType === 'REVOKE'
              ? processCancel({
                processInstanceId: processIdInfo.processInstanceId,
                revokeReason: state.approveRemark
              })
              : setProcessApproval(data)
      usedAPi
          .then(() => {
            // 成功清空前端缓存
            message.success(t('handleSuccess'))
            // 发起成功后，页面跳转到我的流程
            router.replace(
                getAppBaseUrl() + `${import.meta.env.VITE_PUBLIC_PATH}/allin-app/allin-workflow-web/process${
                    state.approvalActionType === 'REVOKE' ? '?type='+ApproveTabTypeEnum.MyInitiated : ''
                }`
            )
          })
          .finally(() => {
            state.confirmApprovalLoading = false
          })
      // })
    }
    // 处理流程退回，如果流程退回至申请人重新提交表单时也需要再次调用退回接口
    const handleApprovalBackSubmit = (isBack = true) => {
      // const { approveNodeKey, processInstanceId, taskId, operatorId, operatorName } =
      //     processDetail.value!.approveInfo
      const targetNodeId = !isStartNode.value ? state.backTargetNode : approveNodeKey
      if (isNullOrEmpty(targetNodeId)) {
        message.error(t('workflow.checkError.noSelectBackNode'))
        return
      }
      // 判断退回时是否有审批意见,流程退回之后在提交没有审批意见
      if (isBack && isNullOrEmpty(state.approveRemark)) {
        message.error(t('workflow.approveRemarkEmpty'))
        return
      }

      state.confirmApprovalLoading = true
      processInstanceRollback(parameter)
          .then(() => {
            // 清空前端缓存
            message.success(t('handleSuccess'))
            // 发起成功后，页面跳转到我的流程 -> 我处理的 tab
            router.replace(
                getAppBaseUrl() + import.meta.env.VITE_PUBLIC_PATH + '/allin-app/allin-workflow-web/process'
            )
          })
          .finally(() => {
            state.confirmApprovalLoading = false
          })
    }
    // 审批策略对象
    const approvalStrategyMap: Record<ApprovalActionType, ApprovalStrategy> = {
      // 同意
      APPROVE: {
        icon: 'check-circle-outlined',
        title: t('confirm'),
        action: handleApproveRejectRevokeConfirm,
        handleApprove: () => {
          state.approvalCommentsModalVisible = true
          state.approveRemark = t('workflow.actions.agree')
        }
      },
      // 拒绝
      REJECT: {
        isDanger: true,
        icon: 'close-circle-outlined',
        title: t('workflow.actions.refuse'),
        action: handleApproveRejectRevokeConfirm,
        handleApprove: () => {
          state.approvalCommentsModalVisible = true
          state.approveRemark = t('workflow.actions.refuse')
        }
      },
      // 回退
      ROLLBACK: {
        isDanger: true,
        icon: 'rollback-outlined',
        title: t('workflow.actions.back'),
        action: handleApproveRejectRevokeConfirm,
        handleApprove: () => {
          // 回退,默认留言
          state.approvalCommentsModalVisible = true
          state.approveRemark = t('workflow.actions.back')
        }
      },
      SUBMIT: {
        icon: '',
        title: '',
        action: () => {},
        handleApprove: () => {
          handleApprovalBackSubmit(false)
        }
      },
      // 催办
      URGE: {
        icon: '',
        title: '',
        action: () => {},
        handleApprove: () => {
          state.confirmApprovalLoading = true
          setProcessUrge(processIdInfo.processInstanceId)
              .then(() => {
                // 成功清空前端缓存
                message.success(t('urgeSuccess'))
              })
              .finally(() => {
                state.confirmApprovalLoading = false
              })
        }
      },
      // 撤销
      REVOKE: {
        icon: 'close-circle-outlined',
        title: t('workflow.actions.undo'),
        action: handleApproveRejectRevokeConfirm,
        handleApprove: () => {
          state.approvalCommentsModalVisible = true
          state.approveRemark = t('workflow.actions.undo')
        }
      }
    }
    // 当前审批动作类型
    const currentApproveAction = computed<ApprovalStrategy>(() => {
      return approvalStrategyMap[state.approvalActionType]
    })
    // 处理各种审批按钮点击
    const handleApproveButtonClick = (approvalAction: ApprovalActionType) => {
      state.approvalActionType = approvalAction
      approvalStrategyMap[approvalAction].handleApprove()
    }
    // 关闭审批意见弹窗
    const handleCancelApprove = () => {
      state.approvalCommentsModalVisible = false
    }
    /**
     * 回退节点选择发生变化
     */
    const handleBackNodeChange = value => {
      state.backTargetNode = value
    }

    const getContainer = () => {
      return document.getElementById('process-detail-form')
    }
    const handleBack = () => {
      router.replace(
          getAppBaseUrl() + `${import.meta.env.VITE_PUBLIC_PATH}/allin-app/allin-workflow-web/process?type=${
              processIdInfo.processStatus
          }`
      )
    }
    return {
      t,
      formRef,
      isNullOrEmpty,
      title,
      state,
      processIdInfo,
      isInitiatorUser,
      isShowUrge,
      isMinePage,
      isCurrentOperatorUser,
      isStartNode,
      isOrganization,
      processInstanceId,
      processDetail,
      currentApproveAction,
      handleApproveButtonClick,
      handleCancelApprove,
      handleBackNodeChange,
      handleBack,
      getContainer
    }
  }
})
</script>

<style lang="less" scoped>
.process-detail-form {
  height: 100%;
  background: #f1f3f4;

  &-row {
    height: 100%;
  }

  &-col {
    height: 100%;
    display: flex;
    flex-direction: column;
  }

  .approval-history-wrapper {
    background-color: #fafbfc;
  }

  &-header {
    position: relative;
    background: #fff;
    display: flex;
    height: 45px;
    align-items: center;
    border-bottom: 1px solid #e1e4ed;
    .back-area {
      border-right: 1px solid #e1e4ed;
      margin-right: 15px;
      .back-btn {
        font-size: 12px;
      }
    }

    &-title {
      //抹平不同长度标题造成的tabs位置变化的问题
      height: 45px;
      line-height: 45px;
      font-weight: bold;
      color: #8e97a8;
      font-size: 14px;

      & > span:nth-child(2) {
        color: #0d0000;
      }
    }

    &-header-tab {
      flex: 1;
      display: flex;
      justify-content: center;
      height: 45px;
      align-items: flex-end;

      .tab {
        margin-right: 60px;
        padding: 0 10px 10px;
        border-bottom: 2px solid #fff;
        cursor: pointer;

        &.active {
          border-bottom: 2px solid #3875ff;
        }
      }
    }
  }

  &-content {
    background: #fff;
    flex: 1;
    overflow: auto;
    position: relative;
    width: 100%;
    margin: 0;
    padding: 20px;
    .main-root {
      padding-bottom: 48px;
      height: calc(100% - 48px);
    }

    &-operate {
      text-align: center;
      position: absolute;
      bottom: 0;
      left: 0;
      width: 100%;
      padding: 15px 0;
      border-top: 1px solid #d9d9d9;
      background: #fff;
    }
  }

  &-content-wide {
    width: 100%;
    height: 100%;
    background: #fff;
    padding-bottom: 60px;
    overflow: auto;
  }
}

:deep(.@{ant-prefix}-timeline-item-head-custom) {
  background: rgba(0, 0, 0, 0);
}

:deep(.approval-comments-modal .@{ant-prefix}-modal-title) {
  font-weight: bold;
  color: #262626;
}
:deep(.approval-comments-modal .@{ant-prefix}-modal-body) {
  padding: 12px 24px;
  .approval-comments {
    color: #595959;
  }
  textarea.ant3-input {
    color: #262626;
    margin-top: 12px;
  }
  .ant3-input:focus, .ant3-input-focused,
  .ant3-input:hover {
    border-color: #3875ff;
  }
  textarea.ant3-input {
    min-height: 163px;
  }
}
:deep(.approval-comments-modal .@{ant-prefix}-modal-footer) {
  padding: 16px 24px;
}
</style>

<i18n>
zh-CN:
  noProcessError: 没有获取到该流程信息
  noProcessDataError: 没有获取到流转表单数据
  handleSuccess: 操作成功
  urgeSuccess: 催办成功
en-US:
  noProcessError: The process information was not obtained
  noProcessDataError: No flow form data obtained
  handleSuccess: Handle success
  urgeSuccess: Urge Success
</i18n>
